Server IP Ranges
클라우드 제공자 IP 대역 검증 Kotlin 라이브러리
TL;DR
- 클라우드 제공자(AWS, GCP, Azure 등)의 IP 대역을 식별하고 접근 제한에 활용할 수 있는 Kotlin 라이브러리입니다.
- 공개 API 어뷰징 방지를 위해 클라우드 대역 기반 차단이 필요했던 경험을 바탕으로, 최신화된 IP 대역 반영과 검증 성능 최적화를 목표로 설계하였습니다.
- IP 대역 수집·저장 파이프라인과 메모리 내 검증 엔진으로 구성되며, Spring Boot 등 기존 JVM 서비스에 라이브러리 형태로 간편히 통합할 수 있습니다.
- 사내 서비스 도입 경험을 토대로 오픈 소스로 공개하였습니다.
기획
배경
이 프로젝트는 사내에서 운영하던 공개 API 서비스의 어뷰징 방지를 위해 구축했던 IP 차단 시스템을 모태로 시작되었습니다.
해당 서비스는 주요 포털 검색 결과에 빌트인 형태로 제공되어 데이터 조회를 제공해주는 서비스로, 일 50만 건 이상의 트래픽을 처리하고 있었습니다.
누구나 접근 가능한 공개 서비스의 특성 상, 매크로와 스크래핑 등의 다양한 방식을 동원한 대규모 어뷰징 트래픽은 피할 수 없었습니다. 이는 서비스 지표 왜곡을 넘어 서비스와 연결된 코어 서비스에도 영향을 주었기에 운영 안정성에 큰 위협이 되었습니다.
초기에는 IP별 Rate Limiting을 도입하여 대응했으나 클라우드 환경의 유동 IP를 이용한 IP 로테이션에는 대응할 수 없었습니다. 결국 클라우드 우회 공격의 원천 차단을 위해 클라우드 대역 자체를 선별할 수 있는 수단을 개발해야 했습니다.
목표
1. 최신화된 IP 대역 제공
클라우드 제공자는 네트워크와 서비스 상황에 따라 수시로 IP 대역을 변경합니다. 오늘 IP 대역을 모두 차단했다 하더라도, 내일이면 새로운 대역에서 어뷰징 공격을 받을 수 있습니다.
변칙적인 어뷰징의 원천 차단을 위해서는 클라우드 제공자의 IP 대역 업데이트를 실시간으로 반영할 수 있어야 했습니다.
2. CPU / 메모리 성능 최적화
클라우드 제공자는 전 세계에 걸쳐 수많은 인프라를 운영하고 있습니다. 매번 이 모든 서버의 수많은 IP 대역을 전부 가져와 메모리에 적재한다면 그것 자체로 서버에 큰 부하가 됩니다.
또한, 검증할 IP가 들어올 때마다 모든 후보군에 일일히 대입한다면 높은 트래픽을 처리하는 환경에서 높은 레이턴시를 예상할 수 있습니다.
위 문제들을 해결하기 위하여 IP 데이터를 사용 사례에 맞게 경량화하고, 검증 속도를 높일 수 있도록 데이터 구조를 최적화할 필요가 있었습니다.
3. 기존 서비스와의 간편한 통합
본 프로젝트가 목표하는 기능은 ‘특정 IP가 클라우드 대역인지 검증하는 Bool 함수’ 정도로 요약할 수 있었기에, 별도의 서버를 구축하는 것은 오버 엔지니어링이라고 판단했습니다.
최소화된 간단한 인터페이스를 제공하는 동시에 Spring Boot로 구성된 기존 기술 스택과 빠르게 통합될 수 있어야 했기에 이를 모두 만족하는 라이브러리 형태를 채택했습니다.
개발
기술 스택
본 프로젝트는 아래와 같은 장점들을 이유로 Kotlin으로 작성했습니다.
- 기존
JVM-Spring기반 서비스와의 100% 호환 - Kotlin-first
Kotlin+Spring환경 지원 - 외부 API / 파일 IO 처리 시 Null 타입 안정성
kotlinx.serialization활용 직렬화 처리- 간결한 문법을 통한 로직 가독성
- 확장 시 코루틴 비동기 처리 용이
아키텍처
본 프로젝트의 아키텍처는 크게 클라우드 제공자의 IP 대역을 수집하여 저장하는 부분과 저장한 IP 대역을 불러와서 검증하는 부분 두 가지로 나뉩니다.
클라우드 IP 대역 수집

클라우드 제공자가 공개하는 CIDR 형식의 IP 대역 데이터를 파싱하여 사전 정의된 분류 규칙(Provider, Region)에 맞게 정제합니다.
이후, 검증에 사용할 수 있도록 CIDR을 정규식으로 변환하여 JSON 파일의 형태로 저장합니다. 검증 시, 라이브러리는 본 파일에 저장된 정규식을 읽어 IP를 검증하게 됩니다.
백업 및 이력 기록을 위하여 정제된 CIDR 데이터 원본도 JSON 형태로 저장합니다.
IP 대역 검증

사용자 입장에서 필요한 기능이 단순한 만큼, 복잡한 구현을 추상화하여 최소한의 인터페이스를 제공하였습니다. 사용자는 isServerIP 함수만 호출하여 IP가 클라우드 대역인지 검증할 수 있습니다. 또한, Provider, Region 파라미터를 전달하여 검증 조건을 부여할 수 있습니다.
사용자가 IP 검증을 요청하면, 라이브러리는 로컬에 저장된 Map 형식의 Provider별 정규식 캐시를 먼저 확인합니다.
캐시가 존재할 시 Provider별 정규식 목록을 반환하고, 라이브러리는 대역 정규식 중 일치하는 대역이 있는지 검증하여 결과를 응답합니다. 대역 단위로 포함 여부를 확인해야 하므로 전체 목록에 대한 검사가 진행됩니다.
캐시가 존재하지 않을 시 JSON 파일에 저장된 Provider의 정규식들을 읽어와 캐시에 적재합니다.
트러블 슈팅
1. 대역 데이터 저장 방식
클라우드는 넓은 대역의 IP를 지원합니다. 그렇기에 대역에 대응하는 모든 IP를 일일히 String으로 저장하고 불러온다면 공간을 과하게 차지하는 것은 물론, 검증 속도도 매우 느려지는 상황을 예상할 수 있었습니다. 이를 해결하기 위해서 적은 공간을 차지하도록 대역을 압축할 수 있어야 했습니다.
클라우드 제공자들은 대역을 나타내는 CIDR 형식으로 공개합니다. 여기에서 착안하여 CIDR을 정규식으로 변환하는 방식을 떠올리게 되었습니다. 정규식을 사용할 경우, 전체 대역 데이터를 한 줄의 문자열로 99.97% 이상 압축할 수 있으며 한 번의 연산으로 IP가 대역에 포함되는지 검증할 수 있습니다.
2. 컴퓨팅 자원 관리
그러나, 아무리 대역을 압축하더라도 여러 클라우드들의 대역 데이터를 모두 메모리에 올린다면 결코 적지 않은 용량을 차지하게 됩니다.
이를 해결하기 위해, 대역 정규식 파일을 디스크에 저장하고 필요할 때만 읽어오는 지연 로딩 방식을 채택하였습니다. 이를 통해 메모리에 모든 정규식 데이터를 가지고 있을 필요 없이 필요한 부분만 읽어서 로딩할 수 있게 됩니다. 또한, 정규식 데이터가 인스턴스의 실행과 독립적으로 저장되기에 인스턴스를 재시작할 때마다 무거운 정규식 데이터 생성을 진행할 필요가 없어집니다.
하지만 단순 지연 로딩으로만 구현한다면, 많은 디스크 I/O가 발생하기에 많은 트래픽이 발생하는 환경에서는 서버에 많은 부담을 주고, 높은 레이턴시를 예상할 수 있었습니다. 이를 해결하기 위해서 데이터를 메모리에 캐싱할 필요가 있었습니다.
그렇다면 어떤 기준으로 데이터를 캐싱해야 할까요?
개별 대역을 캐싱할 수는 없었습니다. 클라우드 서버의 IP는 Region 할당 대역 내에서 예측할 수 없이 바뀌기 때문에 공격자가 다른 대역으로 바꾸어 요청한다면 캐싱된 대역은 의미가 없어집니다.
그렇다고 Region을 기준으로 선택적인 캐싱을 할 수도 없었습니다. 대부분의 사용 사례의 경우, 트래픽의 Region 지정에 대한 수요가 없거나 예측 불가능하기 때문입니다.
그렇기에 최종적으로 Provider 단위 캐싱을 선택하였습니다. 각 Provider에 대한 검증 요청 시, 최초에만 디스크에서 읽어 메모리에 적재하고 이후에는 캐시된 데이터를 사용합니다. 이를 통해 Provider를 지정하여 검증할 경우의 디스크 I/O를 1회로 제한했습니다.
Provider를 지정하지 않은 검증 요청인 경우, 결국 모든 Provider의 대역에 대한 검증이 필요해 모든 Provider 데이터를 메모리에 캐싱합니다. 이러한 경우 지연 로딩의 메모리 저감이 제한적이기 때문에, 먼저 전체 검증으로 운영한 뒤 검증 통계를 보고 실제로 필요한 Provider만 지정해 검증하도록 전환하는 방식을 권장합니다.
3. 클라우드 IP 변동성 대응
앞서 목표에서 설명하였듯, 클라우드의 IP 대역은 수시로 변경됩니다.
이를 반영하기 위해 IP 대역 파일을 갱신하는 함수를 제공하여 라이브러리의 버전과 관계 없이 런타임에 대역을 업데이트할 수 있도록 구성했습니다.
이를 통해 인스턴스 재시작이나 라이브러리 업데이트 없이도 최신 대역을 반영할 수 있으며 스케줄링이나 이벤트 트리거 등 애플리케이션이 원하는 시점에 갱신 로직을 넣을 수 있습니다.
결과
사내에 도입한 라이브러리를 범용적으로 사용할 수 있도록 바꾸어 오픈 소스로 공개했습니다.
문서 개선, 비동기 처리 추가 등 해야 할 작업들이 아직 남아 있습니다. 하나씩 해결하며 발전시켜 나가려고 합니다. 기여는 언제나 환영입니다!